home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
C/C++ Users Group Library 1996 July
/
C-C++ Users Group Library July 1996.iso
/
listings
/
v_09_12
/
9n12064a
< prev
next >
Wrap
Text File
|
1991-07-25
|
19KB
|
615 lines
/*** LISTING 1 ** UARTAPI.C **************************
Application Programming Interface for
UART Asynch Driver.
*****************************************************/
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <dos.h>
#include "uart.h"
#include "uartmacs.c"
/* unused interrupt vector to redirect Ctrl-Break to */
#define UNUSEDVECT 0x48
/* Ctrl-Break vector */
#define CTRL_BRKVECT 0x23
/* Table for converting baud rate to divisor
settings */
static struct
{
unsigned long baud_rate;
unsigned char divisor_high_byte;
unsigned char divisor_low_byte;
} gas_baud_to_divisor[] =
{
{ 50L, 0x09, 0x00 },
{ 75L, 0x06, 0x00 },
{ 110L, 0x04, 0x17 },
{ 134L, 0x03, 0x59 },
{ 150L, 0x03, 0x00 },
{ 300L, 0x01, 0x80 },
{ 600L, 0x00, 0xC0 },
{ 1200L, 0x00, 0x60 },
{ 1800L, 0x00, 0x40 },
{ 2000L, 0x00, 0x3A },
{ 2400L, 0x00, 0x30 },
{ 3600L, 0x00, 0x20 },
{ 4800L, 0x00, 0x18 },
{ 7200L, 0x00, 0x10 },
{ 9600L, 0x00, 0x0C },
{ 19200L, 0x00, 0x06 },
{ 38400L, 0x00, 0x03 },
{ 57600L, 0x00, 0x02 },
{ 115200L, 0x00, 0x01 },
{ 0L, 0x00, 0x00 },
} ;
/* Space to save original asynch interrupt vector */
static void (interrupt far * gp_orig_asynch_vector)();
/* to save original Ctrl-Break vector */
static void (interrupt far *gp_ctrlbrk_vector)();
/*****************************************************
rc = Init_UART()
rc = 1 : UART(s) intialized OK
rc = -1: Failure in initialization.
Before calling this function, you must allocate and
initialize the gp_port_info array to describe
the UART(s) you want to drive, and you must set
g_uart_irq to the IRQ level used (all ports must
use the same IRQ level).
This function latches the UART's interrupt driver
into the system interrupt table and initializes the
UART(s). If successful, it registers the
Exit_UART function to be called during system
shutdown.
*****************************************************/
int Init_UART(void)
{
static char a_funcname[] = "Init_UART:";
register int value_from_port;
unsigned int i;
int retcode;
unsigned char cur_port;
struct t_port_info *p_cur_port_info;
void (interrupt far * p_unusedvect)();
/* Verify that calling program has initialized
info structures and variables */
if (g_num_ports < 1)
{
fprintf(stderr,"%s g_num_ports (%u) < 1\n",
a_funcname,g_num_ports);
return(-1);
}
if (gp_port_info == NULL)
{
fprintf(stderr,"%s gp_port_info is NULL\n",
a_funcname);
return(-1);
}
if ( (g_uart_irq < 3) || (g_uart_irq > 7) )
{
fprintf(stderr,"%s g_uart_irq (%u) not 3-7\n",
a_funcname,g_uart_irq);
return(-1);
}
/* Point at entry for first port */
p_cur_port_info = gp_port_info;
/* Loop through array of port info entries and
initialize each port */
for (cur_port=1;cur_port<=g_num_ports;cur_port++)
{
/* Initialize internal variables in port
info entry */
p_cur_port_info->tx_head = 0;
p_cur_port_info->tx_tail = 0;
p_cur_port_info->rx_head = 0;
p_cur_port_info->rx_tail = 0;
p_cur_port_info->non_int_chars = 0;
/* Check for valid port on this IRQ and at
this base address */
retcode = Test_for_asynch_port(
p_cur_port_info->base_address,g_uart_irq);
if (retcode == -1)
{
fprintf(stderr,
"%s port %u-no UART at %.4Xh on IRQ %u\n",
a_funcname,cur_port,
p_cur_port_info->base_address,
g_uart_irq);
return(-1);
}
/* Validate modem parameters */
if ( (p_cur_port_info->stop_bits < 1) ||
(p_cur_port_info->stop_bits > 2) )
{
fprintf(stderr,
"%s port %u-stop bits (%u) not 1 or 2\n",
a_funcname,cur_port,
p_cur_port_info->stop_bits);
return(-1);
}
switch (p_cur_port_info->parity)
{
case 0 :
case 1 :
case 3 :
break;
default :
fprintf(stderr,
"%s port %u-parity (%u) not 0,1,or 3\n",
a_funcname,cur_port,
p_cur_port_info->parity);
return(-1);
}
if ( (p_cur_port_info->data_bits < 5) ||
(p_cur_port_info->data_bits > 8) )
{
fprintf(stderr,
"%s port %u-data bits (%u) not 5-8\n",
a_funcname,cur_port,
p_cur_port_info->data_bits);
return(-1);
}
/* Translate specified baud rate into
divisor settings */
for (i=0;
gas_baud_to_divisor[i].baud_rate != 0L;
i++)
{
if (p_cur_port_info->baud_rate ==
gas_baud_to_divisor[i].baud_rate)
break;
}
if (gas_baud_to_divisor[i].baud_rate == 0L)
{
fprintf(stderr,
"%s port %u-invalid baud rate %lu\n",
a_funcname,cur_port,
p_cur_port_info->baud_rate);
return(-1);
}
/* Make sure interrupt generation is disabled */
outp(p_cur_port_info->base_address+
INTERRUPT_ENABLE_REGISTER,0x00);
/* Delay for port to catch up */
IO_DELAY(3);
/* Enable writing to divisor latch */
outp(p_cur_port_info->base_address+
LINE_CONTROL_REGISTER,0x80);
/* Delay for port to catch up */
IO_DELAY(3);
/* Set the low byte of the divisor latch */
outp(p_cur_port_info->base_address+
DIV_LATCH_LOW_BYTE,
gas_baud_to_divisor[i].divisor_low_byte);
/* Delay for port to catch up */
IO_DELAY(3);
/* Set the low byte of the divisor latch */
outp(p_cur_port_info->base_address+
DIV_LATCH_HIGH_BYTE,
gas_baud_to_divisor[i].divisor_high_byte);
/* Delay for port to catch up */
IO_DELAY(3);
/* Set parity, data bits, stop bits, and
disable writing to divisor latch */
value_from_port = (int)
( ((p_cur_port_info->stop_bits - 1) << 2 ) |
( p_cur_port_info->parity << 3 ) |
( p_cur_port_info->data_bits - 5 ) ) ;
outp(p_cur_port_info->base_address +
LINE_CONTROL_REGISTER, value_from_port);
/* Delay for port to catch up */
IO_DELAY(3);
/* Initialize Modem Control Register - raise the
OUT2 signal */
outp(p_cur_port_info->base_address +
MODEM_CONTROL_REGISTER,0x08);
/* Delay for port to catch up */
IO_DELAY(3);
/* Enable the FIFO and set it to generate rcv
interrupts only when fifo has more than 8
characters (if UART doesn't have a fifo -
it is an older UART - this instruction will
do nothing). */
outp(p_cur_port_info->base_address +
FIFO_CONTROL_REGISTER,FIFO_ENABLE);
/* Delay for port to catch up */
IO_DELAY(3);
/* Read the interrupt identification register
to determine if the FIFO is enabled. If the
fifo is enabled, use it to transmit multiple
characters. */
value_from_port =
inp(p_cur_port_info->base_address +
INTER